﻿Imports Microsoft.Vbe.Interop
'Define some public constants for the Registry keys

Module IndentCode

    'Define a collection to store the menu item click event handlers

    ' Subroutine: IndentProcedure
    '
    ' Purpose:    Locates the active procedure, checks it for code and indents it
    ''' <summary>
    ''' 过程缩进
    ''' </summary>
    Sub IndentProcedure()
        Dim poVBE As VBE = _VBE
        Dim oVBP As VBProject, oCP As CodePane, oCM As CodeModule
        Dim iStartLine As Long, iEndline As Long, lProcType As Long
        Dim sProc As String
        'On Error Resume Next
        'Try to get the active project
        oVBP = poVBE.ActiveVBProject
        'If we couldn't get it, display a message and quit
        If oVBP Is Nothing Then
            MsgBox("找不到当前模块~", vbOKOnly, "温馨提示")
            Exit Sub
        End If
        If IsO2KVBE() Then
            'If the project is locked, display a message and quit
            If oVBP.Protection = 1 Then
                MsgBox("模块被锁定，无法缩进~", vbOKOnly, "温馨提示")
                Exit Sub
            End If
        End If
        'Try to find the active code pane
        oCP = poVBE.ActiveCodePane
        'If we couldn't get it, display a message and quit
        If oCP Is Nothing Then
            MsgBox("找不到可以缩进的模块~", vbOKOnly, psAPP_TITLE)
            Exit Sub
        End If

        'Check if the module contains any code
        If Not fnHasCode(oCP.CodeModule) Then
            MsgBox("模块中没有代码可以缩进哦~", vbOKOnly, "温馨提示")
            Exit Sub
        End If

        'Get where the current selection is in the module
        oCP.GetSelection(iStartLine, 0, 0, 0)

        oCM = oCP.CodeModule

        'Try to get the procedure name
        sProc = oCM.ProcOfLine(iStartLine, lProcType)

        If sProc <> "" Then
            'If we got a procedure name, find its start and end lines and quit the loop
            iStartLine = oCM.ProcStartLine(sProc, lProcType)
            iEndline = iStartLine + oCM.ProcCountLines(sProc, lProcType) - 1
        Else
            sProc = "Declarations"
            iStartLine = 1
            iEndline = oCM.CountOfDeclarationLines
        End If

        'Store the currently active pane
        CheckActivePane("Store")


        'Just rebuilding a procedure, so pass the procedure name and line boundaries
        RebuildModule(oCM, sProc, iStartLine, iEndline, 0)


        'Restore the currently active pane
        CheckActivePane("Restore")

    End Sub

    '
    ' 功能: 模块缩进
    '
    ' 目的: 对当前模块进行缩进
    ''' <summary>
    ''' 对当前模块进行缩进
    ''' </summary>
    Sub IndentModule()

        Dim poVBE As VBE = _VBE
        Dim oVBP As VBProject, oCP As CodePane, oCM As CodeModule

        ' On Error Resume Next

        '获取当前模块
        oVBP = poVBE.ActiveVBProject

        'If we couldn't get it, display a message and quit
        If oVBP Is Nothing Then
            MsgBox("找不到工程，无所缩进哦~", vbOKOnly, "温馨提示")
            Exit Sub
        End If

        'If the project is locked, display a message and quit
        If IsO2KVBE() Then
            If oVBP.Protection = 1 Then
                MsgBox("模块被锁定，无法缩进", vbOKOnly, "温馨提示")
                Exit Sub
            End If
        End If

        'Try to find the active code pane
        oCP = poVBE.ActiveCodePane

        'If we couldn't get it, display a message and quit
        If oCP Is Nothing Then
            MsgBox("找不到模块！", vbOKOnly, "温馨提示")
            Exit Sub
        End If
        'Check if the module contains any code
        If Not fnHasCode(oCP.CodeModule) Then
            MsgBox("还没有可以缩进的代码哦~", vbOKOnly, "温馨提示")
            Exit Sub
        End If
        'Store the currently active pane
        CheckActivePane("Store")
        oCM = oCP.CodeModule
        'Rebuilding a module, so pass the module name and number of lines therein
        RebuildModule(oCM, oCM.Parent.Name, 1, oCM.CountOfLines, 0)
        'Restore the currently active pane
        CheckActivePane("Restore")
    End Sub

    '
    ' 子例程：缩进项目
    '
    ' 目的：定位活动项目，检查其代码并缩进
    '
    Sub IndentProject()
        Dim poVBE As VBE = _VBE
        Dim oVBP As VBProject, oVBC As Object, oCM As CodeModule
        Dim bSomeCode As Boolean
        Dim lLineCount As Long, lLinesDone As Long

        'On Error Resume Next

        'Try to get the active project
        oVBP = poVBE.ActiveVBProject

        'If we couldn't get it, display a message and quit
        If oVBP Is Nothing Then
            MsgBox("找不到工程~", vbOKOnly, "温馨提示")
            Exit Sub
        End If

        'If the project is locked, display a message and quit
        If IsO2KVBE() Then
            If oVBP.Protection = 1 Then
                MsgBox("模块被锁定，无法缩进~", vbOKOnly, "温馨提示")
                Exit Sub
            End If
        End If

        'Check if the project contains any code, by looping through its VBComponents
        bSomeCode = False
        lLineCount = 0

        For Each oVBC In oVBP.VBComponents
            If fnHasCodeModule(oVBC) Then
                If fnHasCode(oVBC.CodeModule) Then
                    bSomeCode = True
                    lLineCount = lLineCount + oVBC.CodeModule.CountOfLines
                End If
            End If
        Next

        'If we didn't find any code, display a message and quit
        If Not bSomeCode Then
            MsgBox("工程" & oVBP.Name & "没有任何代码", vbOKOnly, "温馨提示")
            Exit Sub
        End If

        'Store the currently active pane
        CheckActivePane("Store")


        'Loop through the components to rebuild their indenting
        For Each oVBC In oVBP.VBComponents
            If fnHasCodeModule(oVBC) Then
                If fnHasCode(oVBC.CodeModule) Then
                    oCM = oVBC.CodeModule
                    'Pass the module name, number of lines, how many have been done already and how many are there in total
                    RebuildModule(oCM, oCM.Parent.Name, 1, oCM.CountOfLines, 0)

                    'Increment the number of lines done for next time round
                    lLinesDone = lLinesDone + oCM.CountOfLines
                End If
            End If
        Next



        'Restore the currently active pane
        CheckActivePane("Restore")

    End Sub


    '
    ' Identify if a given VBComponent has a Code Module to indent
    '
    Private Function fnHasCodeModule(oVBC As VBComponent) As Boolean

        Dim i As Long

        'On Error Resume Next

        Err.Clear()
        i = oVBC.CodeModule.CountOfLines

        fnHasCodeModule = (Err.Number = 0)
        Err.Clear()

    End Function

    '
    ' Checks if the given code module actually contains any code.
    '
    Private Function fnHasCode(oCM As CodeModule) As Boolean

        Dim i As Long

        For i = 1 To oCM.CountOfLines
            If Trim(oCM.Lines(i, 1)) <> "" Then
                fnHasCode = True
                Exit Function
            End If
        Next

    End Function


    '
    ' Stores and restores the visible lines and selection in the active code pane.
    ' When we are replacing code lines, the topline of the code module and the
    ' current selection can become reset.
    '
    Sub CheckActivePane(sType As String)
        Dim poVBE As VBE = _VBE
        'Remember these values for when we come to restore the settings
        Static iStartLine As Long, iStartCol As Long, iEndline As Long, iEndCol As Long, iTop As Long

        'On Error Resume Next

        'Using the active code pane
        With poVBE.ActiveCodePane

            'Store or restore the topline and selection settings as appropriate
            If sType = "Store" Then
                iTop = .TopLine
                .GetSelection(iStartLine, iStartCol, iEndline, iEndCol)
            Else
                .TopLine = iTop
                .SetSelection(iStartLine, iStartCol, iEndline, iEndCol)
            End If
        End With

    End Sub

    '
    ' Identifies if the IDE we're working in is an Office 2000 IDE, or a VB6 IDE
    '
    Function IsO2KVBE()
        Dim poVBE As VBE = _VBE
        Dim s As String
        On Error Resume Next
        Err.Clear()

        s = poVBE.FullName

        IsO2KVBE = (Err.Number <> 0)
        Err.Clear()
        IsO2KVBE = False
    End Function
End Module
